package edu.hawaii.myisern.action;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import edu.hawaii.myisern.collaborations.jaxb.CollaboratingOrganizations;
import edu.hawaii.myisern.collaborations.jaxb.Collaboration;
import edu.hawaii.myisern.collaborations.jaxb.CollaborationTypes;
import edu.hawaii.myisern.collaborations.jaxb.OutcomeTypes;
import edu.hawaii.myisern.collaborations.jaxb.Years;
import edu.hawaii.myisern.model.MyIsernModel;
import edu.hawaii.myisern.organizations.jaxb.Organization;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;


/**
 * Allows for a collaboration to be added or edited. 
 * 
 * @author Ka Yee Leung
 * @author Ivan Wu
 * @author Chiao-Fen Zielinski-Liu
 * @author Michal Zielinski
 * 
 */
public class CollaborationActionBean implements ActionBean {
  /** Required by the ActionBean interface. */
  private ActionBeanContext context;
  
  /** An error string, always displayed, but invisible if empty. */
  private String errorMessage = "";
  
  /** Add label and type. */
  private String addType;
  
  /** Edit label and type. */
  private String editType;
  
  /** Added? */
  private boolean added;
  
  /** Editing? */
  private boolean editing;
  
  /** Edited? */
  private boolean edited;
  
  /** The single MyIsern instance manipulated by all webapp users. */
  private MyIsernModel myIsern = MyIsernModel.getInstance();
  
  /** Collaboration attributes */
  private String name;
  private String collaboratingOrganizations;
  private String collaborationTypes;
  private String years;
  private String outcomeTypes;
  private String description;
  
  private String collaboration = "Collaboration";
  private List<String> collaborationNames;
  private List<String> organizationNames;
  private List<String> selectedOrganizationsNames;
  private String home = "/home.jsp";
  private String selectedOrg;
  
  /**
   * Returns the context. Required by the interface. 
   * 
   * @return the ActionBeanContext.
   */
  public ActionBeanContext getContext() {
    return context;
  }
  
  /**
   * Sets the context. Required by the interface. 
   * 
   * @param context The ActionBeanContext to set. 
   */
  public void setContext(ActionBeanContext context) {
    this.context = context;
  }
  
  /**
   * Returns the error message, which may be empty.
   * Indicates if an error was made adding or editing the collaboration. 
   * 
   * @return The error message. 
   */
  public String getErrorMessage() {
    return this.errorMessage;
  }
  
  /**
   * Returns the appropriate add label.
   * 
   * @return The add label. 
   */
  public String getAddType() {
    return this.addType;
  }
  
  /**
   * Returns the appropriate edit label.
   * 
   * @return The edit label. 
   */
  public String getEditType() {
    return this.editType;
  }
  
  /**
   * Returns the whether the collaboration has been added or not.
   * 
   * @return Whether the collaboration has been added or not. 
   */
  public boolean getAdded() {
    return this.added;
  }
  
  /**
   * Returns the whether the collaboration has been edited or not.
   * 
   * @return Whether the collaboration has been edited or not. 
   */
  public boolean getEdited() {
    return this.edited;
  }
  
  /**
   * Returns the whether the collaboration is being edited or not.
   * 
   * @return Whether the collaboration is being edited or not. 
   */
  public boolean getEditing() {
    return this.editing;
  }
  
  /**
   * Creates and returns the list of collaboration names.
   * 
   * @return The list of collaboration names.
   */
  public List<String> getCollaborationNames() {
    List<Collaboration> collaborationList = myIsern.getCollaborationsDB();
    List<String> collaborationNamesList = new ArrayList<String>();
    for (Collaboration collab : collaborationList) {
      collaborationNamesList.add(collab.getName());
    }
    //Collections.sort(collaborationNamesList);
    this.collaborationNames = collaborationNamesList;
    
    return this.collaborationNames;
  }
  
  /**
   * Creates and returns the list of organization names.
   * 
   * @return The list of collaboration names.
   */
  public List<String> getOrganizationNames() {
    List<Organization> organizationList = myIsern.getOrganizationsDB();
    List<String> orgNamesList = new ArrayList<String>();
    for (Organization orgs : organizationList) {
      orgNamesList.add(orgs.getName());
    }
    //Collections.sort(collaborationNamesList);
    this.organizationNames = orgNamesList;
    
    return this.organizationNames;
  }
  
  /**
   * Sets the names of the collaborations.
   * 
   * @param selectedOrganizationsNames The selected organizations when addiing new collaborations.
   */
  public void setSelectedOrganizationsNames(List<String> selectedOrganizationsNames) {
    this.selectedOrganizationsNames = selectedOrganizationsNames;
  }
  
  /**
   * Returns the name of the collaboration.
   * 
   * @return The name of the collaboration.
   */
  public List<String> getSelectedOrganizationsNames() {
    return this.selectedOrganizationsNames;
  }
  
  
  /**
   * Displays the form to add a collaboration.
   * 
   * @return A Resolution indicating to redisplay the add.jsp page.
   */
  public Resolution collaborationForm() {
    this.addType = collaboration;
    return new ForwardResolution(home);
  }
  
  /**
   * Displays the form to edit a collaboration.
   * 
   * @return A Resolution indicating to redisplay the edit.jsp page.
   */
  public Resolution editCollaborationForm() {
    this.editType = collaboration;
    return new ForwardResolution(home);
  }
  
  /**
   * Sets the name of the collaboration.
   * 
   * @param name The name to set.
   */
  public void setName(String name) {
    this.name = name.trim();
  }
  
  /**
   * Returns the name of the collaboration.
   * 
   * @return The name of the collaboration.
   */
  public String getName() {
    return this.name;
  }
  
  /**
   * Returns the name of the collaborating-organization.
   * 
   * @return The name of the selected organization when editing.
   */
  public String getSelectedOrg() {
    return this.selectedOrg;
  }
  
  /**
   * Sets the selected collaborating-organization.
   * @param selectedOrg The selected org to be edited.
   */
  public void setSelectedOrg(String selectedOrg) {
    this.selectedOrg = selectedOrg.trim();
  }
  
  /**
   * Sets the collaborating organizations of the collaboration.
   * 
   * @param collaboratingOrganizations  The collaborating organizations to set.
   */
  public void setCollaboratingOrganizations(String collaboratingOrganizations) {
    this.collaboratingOrganizations = collaboratingOrganizations;
  }
  
  /**
   * Returns the collaborating organizations of the collaboration.
   * 
   * @return The collaborating organizations of the collaboration.
   */
  public String getCollaboratingOrganizations() {
    return this.collaboratingOrganizations;
  }
  
  /**
   * Sets the collaboration types of the collaboration.
   * 
   * @param collaborationTypes  The collaboration types to set.
   */
  public void setCollaborationTypes(String collaborationTypes) {
    this.collaborationTypes = collaborationTypes;
  }
  
  /**
   * Returns the collaboration types of the collaboration.
   * 
   * @return The collaboration types of the collaboration.
   */
  public String getCollaborationTypes() {
    return this.collaborationTypes;
  }
  
  /**
   * Sets the years of the collaboration.
   * 
   * @param years The years to set.
   */
  public void setYears(String years) {
    this.years = years;
  }
  
  /**
   * Returns the years of the collaboration.
   * 
   * @return The years of the collaboration.
   */
  public String getYears() {
    return this.years;
  }
  
  /**
   * Sets the outcome types of the collaboration.
   * 
   * @param outcomeTypes The outcome types to set.
   */
  public void setOutcomeTypes(String outcomeTypes) {
    this.outcomeTypes = outcomeTypes;
  }
  
  /**
   * Returns the outcome types of the collaboration.
   * 
   * @return The outcome types of the collaboration.
   */
  public String getOutcomeTypes() {
    return this.outcomeTypes;
  }
  
  /**
   * Sets the description of the collaboration.
   * 
   * @param description The description to set.
   */
  public void setDescription(String description) {
    this.description = description.trim();
  }
  
  /**
   * Returns the description of the collaboration.
   * 
   * @return The description of the collaboration.
   */
  public String getDescription() {
    return this.description;
  }
  
  /**
   * Creates and returns a years list from a list string.
   * 
   * @param yearsListString The list string.
   * @return The years list of big integers.
   */
  public List<BigInteger> createYearsList(String yearsListString) {
    List<BigInteger> list = new ArrayList<BigInteger>();
    if ((yearsListString == null) || ("".equals(yearsListString))) {
      this.errorMessage = "Please enter a year.";
      return list;
    }
    
    try {
      String copy = yearsListString;
      String part = "";
      BigInteger year = null;
      while (copy.contains(",")) {
        int stopIndex = copy.indexOf(',');
        part = copy.substring(0, stopIndex);
        copy = copy.substring(stopIndex + 1);
        year = new BigInteger(part.trim());
        list.add(year);
      }
      year = new BigInteger(copy.trim());
      list.add(year);
    }
    catch (java.lang.NumberFormatException error) {
      this.errorMessage = "Invalid year entered. Please enter again: ";
    }
    return list;
  }
  
  /**
   * Adds a collaboration.
   * 
   * @return A Resolution indicating to redisplay the add.jsp page.
   * @throws Exception If problems occur.
   */
  public Resolution add() throws Exception {
    if (this.name == null) {
      this.errorMessage = "Please enter a name.";
      this.addType = collaboration;  
    }
    else if (this.getSelectedOrganizationsNames() == null) {
      this.errorMessage = "Please select a Collaborating-Organization Name";
      this.addType = collaboration;
    }
    else {
      List<Collaboration> list = myIsern.getCollaborationsDB();
      boolean found = false;
      for (Collaboration collaboration : list) {
        if (collaboration.getName().equals(this.name.replace('_', ' '))) {
          found = true;
        }
      }

      if (found) {
        this.errorMessage = "Collaboration already exists. Please edit.";
        this.editType = collaboration;
        this.editing = true;
      }
      else {
        Collaboration newCollaboration = new Collaboration();
        newCollaboration.setName(this.name);
        CollaboratingOrganizations newCollaboratingOrganizations = new CollaboratingOrganizations();
        newCollaboratingOrganizations.getCollaboratingOrganization()
        .addAll(this.selectedOrganizationsNames);
        newCollaboration.setCollaboratingOrganizations(newCollaboratingOrganizations);
        CollaborationTypes newCollaborationTypes = new CollaborationTypes();
        newCollaborationTypes.getCollaborationType().addAll(myIsern.createList(collaborationTypes));
        newCollaboration.setCollaborationTypes(newCollaborationTypes);
        Years newYears = new Years();
        newYears.getYear().addAll(createYearsList(this.years));
        newCollaboration.setYears(newYears);
        OutcomeTypes newOutcomeTypes = new OutcomeTypes();
        newOutcomeTypes.getOutcomeType().addAll(myIsern.createList(this.outcomeTypes));
        newCollaboration.setOutcomeTypes(newOutcomeTypes);
        newCollaboration.setDescription(this.description);

        //myIsern.addCollaboration(newCollaboration);
        if ((years == null) || ("".equals(years)) ||
            (this.errorMessage.equals("Invalid year entered. Please enter again: "))) {
          this.addType = collaboration;
        }
        else {
          myIsern.addCollaborationDB(newCollaboration);
          this.added = true;
        }
      }
    }
    //this.addType = collaboration;    
    return new ForwardResolution(home);
  }
  
  /**
   * Displays the information to edit.
   * 
   * @return A resolution indicating to redisplay the edit.jsp page.
   * @throws Exception If problems occur.
   */
  public Resolution displayEdit() throws Exception {
    List<Collaboration> list = myIsern.getCollaborationsDB();
    Collaboration editCollaboration = new Collaboration();
    boolean found = false;
    for (Collaboration collaboration : list) {
      if (collaboration.getName().equals(this.name.replace('_', ' '))) {
        editCollaboration = collaboration;
        found = true;
      }
    }

    if (found) {
      this.selectedOrganizationsNames = editCollaboration
          .getCollaboratingOrganizations().getCollaboratingOrganization();
      this.collaborationTypes = myIsern.createListString(editCollaboration.getCollaborationTypes()
          .getCollaborationType());

      List<BigInteger> yearsList = editCollaboration.getYears().getYear();
      int listSize = yearsList.size();
      int listCount = 1;
      StringBuffer yearNames = new StringBuffer();
      for (BigInteger year : yearsList) {
        yearNames.append(year.toString());
        if (listCount < listSize) {
          String separator = ", ";
          yearNames.append(separator);
        }
        listCount++;
      }

      this.years = yearNames.toString();
      this.outcomeTypes = myIsern.createListString(editCollaboration.getOutcomeTypes()
          .getOutcomeType());
      this.description = editCollaboration.getDescription();

      this.editing = true;
    }
    
    this.editType = collaboration;    
    return new ForwardResolution(home);
  }
  
  /**
   * Edits a collaboration.
   * 
   * @return A resolution indicating to redisplay the edit.jsp page.
   * @throws Exception If problems occur.
   */
  public Resolution edit() throws Exception {
    List<Collaboration> list = myIsern.getCollaborationsDB();
    //int count = 0;
    Collaboration editCollaboration = new Collaboration();
    for (Collaboration collaboration : list) {
      if (collaboration.getName().equals(this.name.replace('_', ' '))) {
        editCollaboration = collaboration;
        //count = list.indexOf(collaboration);
      }
    }
    
    editCollaboration.setName(this.name);
    CollaborationTypes newCollaborationTypes = new CollaborationTypes();
    newCollaborationTypes.getCollaborationType().addAll(myIsern.createList(collaborationTypes));
    editCollaboration.setCollaborationTypes(newCollaborationTypes);
    Years newYears = new Years();
    newYears.getYear().addAll(createYearsList(this.years));
    editCollaboration.setYears(newYears);
    OutcomeTypes newOutcomeTypes = new OutcomeTypes();
    newOutcomeTypes.getOutcomeType().addAll(myIsern.createList(this.outcomeTypes));
    editCollaboration.setOutcomeTypes(newOutcomeTypes);
    editCollaboration.setDescription(this.description);
    
    //myIsern.editCollaboration(count, editCollaboration);
    if ((years == null) || ("".equals(years)) ||
        (this.errorMessage.equals("Invalid year entered. Please enter again: "))) {
      this.editType = collaboration; 
      this.editing = true;
      this.selectedOrganizationsNames = 
        editCollaboration.getCollaboratingOrganizations().getCollaboratingOrganization();
    }
    else {
      myIsern.editCollaborationDB(editCollaboration);
      this.edited = true;
      this.editing = true;
    }
    
    //this.editType = collaboration;    
    return new ForwardResolution(home);
  }
  
  /**
   * Removes the collaboration.
   * 
   * @return A resolution indicating to redisplay the add.jsp or edit.jsp page.
   * @throws Exception If problems occur.
   */
  public Resolution remove() throws Exception {    
    myIsern.removeCollaborationDB(this.name);
    
    this.errorMessage = this.name + " has been deleted.";
    return new ForwardResolution(home);
  }
  
  /**
   * Deletes the selected affiliated researcher when editing organizations.
   * 
   * @return redisplay home.jsp.
   */
  public Resolution editSelectedColOrg() {
    List<Collaboration> list = myIsern.getCollaborationsDB();
    Collaboration editCollaboration = new Collaboration();

    for (Collaboration collaboration : list) {
      if (collaboration.getName().equals(this.name.replace('_', ' '))) {
        editCollaboration = collaboration;
      }
    }
    if (this.selectedOrg == null) {
      this.selectedOrg = "";
    }
    editCollaboration.getCollaboratingOrganizations().
    getCollaboratingOrganization().remove(this.selectedOrg);
    this.selectedOrganizationsNames = 
      editCollaboration.getCollaboratingOrganizations().getCollaboratingOrganization();
    myIsern.editCollaborationDB(editCollaboration);
    this.editType = collaboration;
    this.editing = true;
    return new ForwardResolution(home);
  }
  
  /**
   * Adds the selected affiliated researcher when editing organizations.
   * 
   * @return redisplay home.jsp.
   */
  public Resolution addSelectedColOrg() {
    List<Collaboration> list = myIsern.getCollaborationsDB();
    Collaboration editCollaboration = new Collaboration();

    for (Collaboration collaboration : list) {
      if (collaboration.getName().equals(this.name.replace('_', ' '))) {
        editCollaboration = collaboration;
      }
    }
    if (this.collaboratingOrganizations == null) {
      this.collaboratingOrganizations = "";
    }
    editCollaboration.getCollaboratingOrganizations().
    getCollaboratingOrganization().add(this.collaboratingOrganizations);
    this.selectedOrganizationsNames = 
      editCollaboration.getCollaboratingOrganizations().getCollaboratingOrganization();
    myIsern.editCollaborationDB(editCollaboration);
    this.editType = collaboration;
    this.editing = true;
    return new ForwardResolution(home);
  }
}